﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;

namespace NeroConnect.Network
{
	class HttpListener : IListener
	{
        bool _stop = false;
        private MiniHttpServer.IHttpListener _listener;

        private object _cs = new object();
        private System.Threading.AutoResetEvent _event_request_received = new System.Threading.AutoResetEvent(false);
        private System.Collections.Generic.List<HttpListenerContext> _list_contexts = new System.Collections.Generic.List<HttpListenerContext>();
        private delegate IListenerContext AsyncGetContextCaller();
        private AsyncGetContextCaller _asyncGetContextCaller;


		public HttpListener(int port)
		{
            _asyncGetContextCaller = new AsyncGetContextCaller(this.GetContext);
            _listener = MiniHttpServer.IHttpListener.Create(System.Net.IPAddress.Any, port);
            _listener.SetRequestReceiver(new MiniHttpServer.IHttpListener.RequestReceiverDelegate(this._listener_RequestReceived));
		}

		~HttpListener()
		{
            Stop();
		}

        private void _listener_RequestReceived(MiniHttpServer.IHttpContext context)
        {
             lock (_cs)
            {
                _list_contexts.Add(new HttpListenerContext(this, context));
                _event_request_received.Set();
            }
        }

        public bool IsListening
		{
			get { return _listener.IsStarted; }
		}

		public void Abort()
		{
            Stop();
		}

		public void Close()
		{
			Stop();
		}

		public IListenerContext GetContext()
		{
            IListenerContext result = null;
            bool needRetry = false;
            do 
            {
                needRetry = false;
                lock (_cs)
                {
                    if (_list_contexts.Count > 0)
                    {
                        result = _list_contexts[0];
                        _list_contexts.RemoveAt(0);
                    }
                    else
                    {
                        needRetry = true;
                    }
                }
                if (needRetry && !_stop)
                {
                    _event_request_received.WaitOne(new System.TimeSpan(5000));
                }
            } while (needRetry && !_stop);

            return result;
		}

        public IAsyncResult BeginGetContext(AsyncCallback callback, object state)
        {
            return _asyncGetContextCaller.BeginInvoke(callback, state);
        }

        public IListenerContext EndGetContext(IAsyncResult asyncResult)
        {
            return _asyncGetContextCaller.EndInvoke(asyncResult);
        }
        
        public void Start()
		{
            _stop = false;
			_listener.Start();
		}

		public void Stop()
		{
            _listener.Stop();
            // unblock any pending waiting "GetContext" calls (to reduce the shutdown time)
            _stop = true;
            _event_request_received.Set();
		}

		public bool IgnoreWriteExceptions
		{
			get
			{
                return true;
			}
			set
			{
                // ignore
			}
		}

		public IList<IPAddress> LocalIPAddresses
		{
			get
			{
				IList<IPAddress> addressList = new List<IPAddress>();
				NetworkInterface[] networkInterfaces = NetworkInterface.GetAllNetworkInterfaces();
				foreach (NetworkInterface networkInterface in networkInterfaces)
				{
					IPInterfaceProperties properties = networkInterface.GetIPProperties();
					foreach (UnicastIPAddressInformation addressInformation in properties.UnicastAddresses)
					{
						if (IPAddress.IsLoopback(addressInformation.Address) || addressInformation.Address.AddressFamily == AddressFamily.InterNetworkV6)
							continue;
						if (addressInformation.Address.AddressFamily != AddressFamily.InterNetwork)
							continue;
						addressList.Add(addressInformation.Address);
					}
				}
				return addressList;
			}
		}

		public void Dispose()
		{
            Stop();
 		}

	}

    //class HttpListener : IListener
    //{
    //    System.Net.HttpListener _listener;

    //    public HttpListener(int port)
    //    {
    //        _listener = new System.Net.HttpListener();
    //        string prefix = string.Format(CultureInfo.InvariantCulture, "http://+:{0}/", port);
    //        _listener.Prefixes.Add(prefix);
    //    }

    //    ~HttpListener()
    //    {
    //        Dispose(false);
    //    }

    //    public bool IsListening
    //    {
    //        get { return _listener.IsListening; }
    //    }

    //    public void Abort()
    //    {
    //        _listener.Abort();
    //    }

    //    public IAsyncResult BeginGetContext(AsyncCallback callback, object state)
    //    {
    //        return _listener.BeginGetContext(callback, state);
    //    }

    //    public void Close()
    //    {
    //        _listener.Close();
    //    }

    //    public IListenerContext EndGetContext(IAsyncResult asyncResult)
    //    {
    //        return new HttpListenerContext(_listener.EndGetContext(asyncResult));
    //    }

    //    public IListenerContext GetContext()
    //    {
    //        return new HttpListenerContext(_listener.GetContext());
    //    }

    //    public void Start()
    //    {
    //        _listener.Start();
    //    }

    //    public void Stop()
    //    {
    //        _listener.Stop();
    //    }

    //    public bool IgnoreWriteExceptions
    //    {
    //        get
    //        {
    //            return _listener.IgnoreWriteExceptions;
    //        }
    //        set
    //        {
    //            _listener.IgnoreWriteExceptions = value;
    //        }
    //    }

    //    public IList<IPAddress> LocalIPAddresses
    //    {
    //        get
    //        {
    //            IList<IPAddress> addressList = new List<IPAddress>();
    //            NetworkInterface[] networkInterfaces = NetworkInterface.GetAllNetworkInterfaces();
    //            foreach (NetworkInterface networkInterface in networkInterfaces)
    //            {
    //                IPInterfaceProperties properties = networkInterface.GetIPProperties();
    //                foreach (UnicastIPAddressInformation addressInformation in properties.UnicastAddresses)
    //                {
    //                    if (IPAddress.IsLoopback(addressInformation.Address) || addressInformation.Address.AddressFamily == AddressFamily.InterNetworkV6)
    //                        continue;
    //                    if (addressInformation.Address.AddressFamily != AddressFamily.InterNetwork)
    //                        continue;
    //                    addressList.Add(addressInformation.Address);
    //                }
    //            }
    //            return addressList;
    //        }
    //    }

    //    public void Dispose()
    //    {
    //        Dispose(true);
    //        GC.SuppressFinalize(this);
    //    }

    //    private void Dispose(bool disposing)
    //    {
    //        if (!IsListening)
    //            return;
    //        if (disposing)
    //            _listener.Close();
    //    }
    //}
}
